﻿using System;
using System.Collections.Generic;

namespace TimetableCSP.Scheduler.Entities
{
	/// <summary>
	/// A base class for constraints in a constraint satisfaction problem.
	/// </summary>
	public abstract class AbstractConstraint
	{
		private int conflictCount = 0;

		/// <summary>
		/// Gets or sets the conflict count.
		/// </summary>
		/// <value>
		/// The conflict count.
		/// </value>
		public int ConflictCount
		{
			get { return conflictCount; }
			set { conflictCount = value; }
		}

		/// <summary>
		/// Generates a summary of conflict counts, grouped by the conflicted constraint.
		/// </summary>
		/// <param name="iteration">The current iteration.</param>
		/// <param name="constraints">The constraints.</param>
		/// <returns>A summary of conflict counts, grouped by the conflicted constraint</returns>
		public static string ConflictInfoToString(int iteration, IEnumerable<AbstractConstraint> constraints)
		{
			const int outputHeadersEveryXIterations = 30;
			const string total = "TOTAL";
			const string iterationHeader = "Iteration";

			bool writeHeaders = (iteration == 1 || (iteration % outputHeadersEveryXIterations) == 0);
			
			string output = "";

			if (iteration == 1)
			{
				output += "Conflicts per constraint type" + Environment.NewLine;
			}

			List<int> constraintNameLength = new List<int>();
			if (writeHeaders)
			{
				output += iterationHeader + " ";
			}
			foreach (AbstractConstraint abstractConstraint in constraints)
			{
				constraintNameLength.Add(abstractConstraint.GetType().Name.Length);
				if (writeHeaders)
				{
					output += abstractConstraint.GetType().Name + " ";
				}
			}
			if (writeHeaders)
			{
				output += total + Environment.NewLine;
			}

			int index = 0;
			int totalCount = 0;
			output += Convert.ToString(iteration).PadLeft(iterationHeader.Length) + " ";
			foreach (AbstractConstraint abstractConstraint in constraints)
			{
				totalCount += abstractConstraint.ConflictCount;
				string count = Convert.ToString(abstractConstraint.ConflictCount);
				int padLength = constraintNameLength[index];
				output += count.PadLeft(padLength, ' ') + " ";
				++index;
			}
			output += Convert.ToString(totalCount).PadLeft(total.Length) + Environment.NewLine;
			return output;
		}
	}
}
